{/* Copyright 2025 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '../../src/Layout';
export default Layout;
import {FunctionAPI} from '../../src/FunctionAPI';
import docs from 'docs:@react-aria/interactions';
import typesDocs from 'docs:@react-types/shared/src/events.d.ts';
import {InterfaceType} from '../../src/types';
export const section = 'Interactions';
export const description = 'Handles move interactions for pointer and keyboard, useful for sliders and drag operations.';

# useMove

<PageDescription>{docs.exports.useMove.description}</PageDescription>

```tsx render
"use client";
import React from 'react';
import {useMove} from 'react-aria';

function Example() {
  const CONTAINER_SIZE = 200;
  const BALL_SIZE = 30;

  let [events, setEvents] = React.useState([]);
  let [color, setColor] = React.useState('black');
  let [position, setPosition] = React.useState({
    x: 0,
    y: 0
  });

  let clamp = pos => Math.min(Math.max(pos, 0), CONTAINER_SIZE - BALL_SIZE);
  let {moveProps} = useMove({
    onMoveStart(e) {
      setColor('red');
      setEvents(events => [`move start with pointerType = ${e.pointerType}`, ...events]);
    },
    onMove(e) {
      setPosition(({x, y}) => {
        // Normally, we want to allow the user to continue
        // dragging outside the box such that they need to
        // drag back over the ball again before it moves.
        // This is handled below by clamping during render.
        // If using the keyboard, however, we need to clamp
        // here so that dragging outside the container and
        // then using the arrow keys works as expected.
        if (e.pointerType === 'keyboard') {
          x = clamp(x);
          y = clamp(y);
        }

        x += e.deltaX;
        y += e.deltaY;
        return {x, y};
      });

      setEvents(events => [`move with pointerType = ${e.pointerType}, deltaX = ${e.deltaX}, deltaY = ${e.deltaY}`, ...events]);
    },
    onMoveEnd(e) {
      setPosition(({x, y}) => {
        // Clamp position on mouse up
        x = clamp(x);
        y = clamp(y);
        return {x, y};
      });
      setColor('black');
      setEvents(events => [`move end with pointerType = ${e.pointerType}`, ...events]);
    }
  });

  return (
    <>
      <div
        style={{
          width: CONTAINER_SIZE,
          height: CONTAINER_SIZE,
          background: 'white',
          border: '1px solid black',
          position: 'relative',
          touchAction: 'none'
        }}>
        <div
          {...moveProps}
          tabIndex={0}
          style={{
            width: BALL_SIZE,
            height: BALL_SIZE,
            borderRadius: '100%',
            position: 'absolute',
            left: clamp(position.x),
            top: clamp(position.y),
            background: color
          }} />
      </div>
      <ul
        style={{
          maxHeight: '200px',
          overflow: 'auto'
        }}>
        {events.map((e, i) => <li key={i}>{e}</li>)}
      </ul>
    </>
  );
}
```

## Features

Move events are emitted after the user presses down and then drags the pointer around. They specify the distance that the pointer traveled since the last event. In addition, after a user focuses the target element, move events are fired when the user presses the arrow keys.

* Handles mouse and touch events
* Handles arrow key presses
* Disables text selection while the user drags

## API

<FunctionAPI function={docs.exports.useMove} links={docs.links} />

### MoveEvents

<InterfaceType {...typesDocs.exports.MoveEvents} />

### MoveResult

<InterfaceType {...docs.exports.MoveResult} />

### MoveEvent

<InterfaceType {...typesDocs.exports.MoveMoveEvent} />
